#include "widget.h"
#include "./ui_widget.h"

#define __DEBUG__ true

#include <QtMultimedia/QSoundEffect>
#include <QtCore/QThread>
#include <QtCore/QList>
#include <QtCore/QRandomGenerator>
#include <QMessageBox>
#include <QDir>
#include <QFile>
#include <QtCore/QElapsedTimer>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

//    //装入点划音频文件
//    playDotDash.setSource(QUrl("qrc:/wav/003.wav"));

//    //设置音量
//    playDotDash.setVolume(0.9);

//    //音效设置为单次播放，不循环
//    playDotDash.setLoopCount(0);

    //数据文件不存在则从资源中拷贝
    QString dbPath = QDir::currentPath() + "/db";
    QString dbFile = dbPath + "/morse.db";
    QFile f0(dbFile);//
    if(!f0.exists()){   //目标文件不存在,则新建目标目录
        QDir d;
        d.mkdir(dbPath);
        if(!QFile::copy(":/db/morse.db", dbFile)){
            QMessageBox::warning(this, "Note", "数据文件拷贝失败 ！");
        }else{
            QFile::setPermissions(dbFile, QFileDevice::ReadOwner | QFileDevice::WriteOwner);
        }
    }

    //打开数据表
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(dbFile);
    db.open();

    qr = new QSqlQuery(db);

    qr->exec("select code from morse where type = 'config' and chracter = 'dot_length' ");
    if(qr->next()){
        ui->leDot->setText(qr->value(0).toString());
    }else{
        qr->exec("insert into morse(chracter, code, type) values ('dot_length', '100', 'config' ) ");
    }

    //设置显示字体大小和颜色
    QFont f = this->font();
    f.setPointSize(f.pointSize() * 5);
    QPalette p;
    p.setColor(QPalette::Text, Qt::blue);

    ui->ptEcho->setPalette(p);
    ui->ptEcho->setFont(f);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{

    bool trans;

    //点划间隔 ＝ 点时长
    sepI = ui->leDot->text().toInt( &trans );
    if(!trans){
        QMessageBox::warning(this, "Note", "无效数字！");
        ui->leDot->setFocus();
        return;
        if(sepI < 10){
            QMessageBox::warning(this, "Note", "数字应该小于 10 ！");
            ui->leDot->setFocus();
            return;
        }
        if(sepI >300){
            QMessageBox::warning(this, "Note", "数字不应该大于 300 ！");
            ui->leDot->setFocus();
            return;
        }
    }

    qr->exec("update morse set code = '" + QString::number(sepI) + "' where  type = 'config' and chracter = 'dot_length' ");

    //字符间隔 ＝ 划时长
    sepO = 3 * sepI;

    //如未设置无限循环，检查预设字符数量是否合理
    if(!ui->ckbInfinite->isChecked()){

        charCount = ui->leCount->text().toInt( &trans );
        if(!trans){
            QMessageBox::warning(this, "Note", "无效数字！");
            ui->leCount->setFocus();
            return;
        }
        if(charCount < 1){
            QMessageBox::warning(this, "Note", "数字应该大于 1 ！");
            ui->leCount->setFocus();
            return;

        }
    }

    //字符范围
    if(!ui->ckbA->isChecked() && !ui->ckbD->isChecked() && !ui->ckbC->isChecked()){
        QMessageBox::warning(this, "Note", "未指定练习范围！");
        return;
    }

    //开始运行之后，禁用一些界面设置
    ui->pushButton->setEnabled(false);
    ui->ckbA->setEnabled(false);
    ui->ckbC->setEnabled(false);
    ui->ckbD->setEnabled(false);
    ui->rbExaminate->setEnabled(false);
    ui->rbExercise->setEnabled(false);
    ui->rbRandom->setEnabled(false);
    ui->rbOrdered->setEnabled(false);

    //是否清除上次测验结果。本次为测试运行，必清。本次为练习，根据选项确定是否清。
    if(ui->ckbClear->isChecked() || ui->rbExaminate->isChecked()){
        if(!qr->exec("update morse set count = 0, correct = 0, error = ''")){
            QMessageBox::warning(this,"Note", "SQL not execute properly.");
        }
    }

    //根据选项，确定本次选择内容
    sq = "select chracter, code from morse where (count = 0 or count <> correct) ";

    if(ui->ckbA->isChecked()){
        sq.append(" and type = 'alphabet'");
    }
    if(ui->ckbD->isChecked()){
        sq.append(" and type = 'digit'");
    }
    if(ui->ckbC->isChecked()){
        sq.append(" and type = 'char'");
    }
    if(ui->rbRandom->isChecked()){
        sq.append(" order by chracter");
    }

    qr->exec(sq);

    //从数据表选择的内容存储到map
    bool hasData = false;
    while(qr->next()){
        hasData = true;
        base[qr->value("chracter").toString()] = qr->value("code").toString();
    }

    if(!hasData){
        QMessageBox::warning(this, "Note", "数据文件无效，请退出重新进入！");
        QFile::remove(QDir::currentPath() + "/db/morse.db");
        return;
    }

    //测试或练习的显示，需要大字体
    QFont f = ui->ptEcho->font();
    f.setPointSize(this->font().pointSize() * 5);
    ui->ptEcho->setFont(f);

    //流程运行状态标志，用于控制循环
    isRun = true;

    //根据选项，进入测试或练习
    if(ui->rbExercise->isChecked()){
        exercise();
    }else if(ui->rbExaminate->isChecked()){
        examinate();
    }else{
        QMessageBox::warning(this, "Note", "程序状态错误！");
        return;

    }

    //运行结束，恢复屏幕
    ui->pushButton->setEnabled(true);
    ui->ckbA->setEnabled(true);
    ui->ckbC->setEnabled(true);
    ui->ckbD->setEnabled(true);
    ui->rbExaminate->setEnabled(true);
    ui->rbExercise->setEnabled(true);
    ui->rbOrdered->setEnabled(true);
    ui->rbRandom->setEnabled(true);

}

void Widget::on_pushButton_2_clicked()
{
    //退出按钮，首先设置停止标志，然后关闭窗口
    isRun = false;
    close();
}


void Widget::on_pushButton_3_clicked()
{
    //停止按钮，设置停止标志
    isRun = false;
}

void Widget::exercise()
{

    //QSoundEffect playDotDash ;
    //装入点划音频文件
    //playDotDash.setSource(QUrl("qrc:/wav/0.3.wav"));

    int max = base.count(); //选择范围字符数量
    int pos = max;          //当前播放位置

    QElapsedTimer elps;

    ui->ptEcho->clear();

    QList <QString> keys = base.keys(); //播放列表的字符

    QSoundEffect playStart ;
    //装入点划音频文件
    playStart.setSource(QUrl("qrc:/wav/blank.wav"));
    playStart.play(); //不如此执行，第一次声音无法播放。
    delay(15);
    playStart.stop();
    delay(15);

    //循环条件：在运行，且窗口未关闭，且 （无限数量选项 或 循环数量未完成）
    while(isRun && !this->isHidden() && (ui->ckbInfinite->isChecked() || charCount > 0 )) {

        //倒计数显示
        if(charCount > 0){
            charCount--;
            ui->leCount->setText(QString::number(charCount));
        }else{
            ui->leCount->setText("0");
        }

        //随机播放或顺序播放
        if(ui->rbRandom->isChecked()){
            pos = r.global()->bounded(max);
        }else{
            pos ++ ;
            if(pos >= max){
                pos = 0;
            }
        }

        QString k = keys[pos];      //显示字符
        QString v = base.value(k);  //点划


        ui->ptEcho->clear();
        ui->ptEcho->insertPlainText( k.toUpper() + " \t " +v );
        qApp->processEvents();

        if(__DEBUG__){
            qDebug()<< "display char : " << k;
            qDebug()<< "display dot/dash : " << v;
        }



        //根据点划数据进行播放
        foreach (QChar c, v) {
            QSoundEffect playDotDash ;

            //装入点划音频文件
            playDotDash.setSource(QUrl("qrc:/wav/base.wav"));
            //playDotDash.play(); //不如此执行，第一次声音无法播放。
            //qApp->processEvents();
            //playDotDash.stop();
            //while(playDotDash.isPlaying()){
            //    qApp->processEvents();
            //}


            if( c == QChar('.')){
                playDotDash.play();

                elps.start();

                while(true){
                    qApp->processEvents();
                    if(elps.elapsed() > sepI){
                        playDotDash.stop();
                        //playDotDash.
                        break;
                    }
                }

                while(playDotDash.isPlaying()){
                    qApp->processEvents();

                }

                //QThread::msleep(sepI);
                delay(sepI);

            }else if(c == '-'){

                playDotDash.play();

                elps.start();

                while(true){
                    qApp->processEvents();
                    if(elps.elapsed() > sepO){
                        playDotDash.stop();
                        break;
                    }
                }

                //QThread::msleep(sepI);
                delay(sepI);

            }
        }

        //QThread::msleep(sepO);
        delay(sepO);
    }
}

void Widget::examinate()
{
    int max = base.count(); //测试范围
    int pos = max;          //当前字符位置，如为顺序播放，可以保证从第一个字符开始。
    QElapsedTimer elps;
    ui->ptEcho->clear();

    QList <QString> keys = base.keys();     //字符列表

    while(isRun && !this->isHidden() && (ui->ckbInfinite->isChecked() || charCount > 0 )) {

        if(charCount > 0){
            charCount--;
            ui->leCount->setText(QString::number(charCount));
        }else{
            ui->leCount->setText("0");
        }

        if(ui->rbRandom->isChecked()){
            pos = r.global()->bounded(max);
        }else{
            pos ++ ;
            if(pos >= max){
                pos = 0;
            }
        }

        currentText = keys[pos];
        QString v = base.value(currentText);

        ui->ptEcho->clear();
        qApp->processEvents();

        QSoundEffect playStart ;
        //装入点划音频文件
        playStart.setSource(QUrl("qrc:/wav/blank.wav"));
        playStart.play(); //不如此执行，第一次声音无法播放。
        delay(150);
        playStart.stop();
        delay(200);

        foreach (QChar c, v) {

            QSoundEffect playDotDash ;
            //装入点划音频文件
            playDotDash.setSource(QUrl("qrc:/wav/base.wav"));

            if( c == QChar('.')){
                playDotDash.play();

                elps.start();

                while(true){
                    qApp->processEvents();
                    if(elps.elapsed() > sepI){
                        playDotDash.stop();
                        //playDotDash.
                        break;
                    }
                }

                while(playDotDash.isPlaying()){
                    qApp->processEvents();

                }
                delay(sepI);
                //QThread::msleep(sepI);

            }else if(c == '-'){

                playDotDash.play();

                elps.start();

                while(true){
                    qApp->processEvents();
                    if(elps.elapsed() > sepO){
                        playDotDash.stop();
                        break;
                    }
                }
                delay(sepI);
                //QThread::msleep(sepI);

            }
        }
        delay(sepO);
        //QThread::msleep(sepO);

        //等待用户输入播放点划的字符
        waitInput = true;
        ui->ptEcho->setFocus();
        while(waitInput){
            //是否有停止按钮消息
            if(!isRun) break;
            qApp->processEvents();
        }
        if(!isRun) break;
    }
    //退出循环之后，设置运行停止标志
    isRun = false;
    ui->ptEcho->clear();
    //准备显示测试结果，重新设置字体
    ui->ptEcho->setFont(this->font());

    qr->exec("select chracter, (count - correct)/1.0 / count * 100 as c , error "
             "from morse where count > 0 and count <> correct order by c desc");
    ui->ptEcho->insertPlainText("字符\t错误率\t错误字符");
    bool hasError = false;
    while(qr->next()){
        hasError = true;
        double rate = qr->value(1).toDouble();
        ui->ptEcho->insertPlainText("\n" + qr->value(0).toString()
                                    + "\t" + QString::number( rate , 'f', 1) + "%\t" + qr->value(2).toString());
    }

    if(!hasError){
        ui->ptEcho->clear();
        ui->ptEcho->insertPlainText("录入字符完全正确！");

    }
}

void Widget::on_ptEcho_textChanged()
{
    //当前如不是运行状态，返回
    if(!isRun) return;

    //录入无效字符，返回
    if(ui->ptEcho->toPlainText().trimmed().isEmpty()) return;

    QString inputC = ui->ptEcho->toPlainText().trimmed().toLower();
    //当前播放字符与录入字符是否一致
    if( currentText == inputC){
        sq = "update morse set count = count + 1, correct = correct + 1 where chracter = '" + currentText + "'";
    }else{
        sq = "update morse set count = count + 1 , error = error || ' " + inputC + "' where chracter = '" + currentText + "'";
    }
    qr->exec(sq);
    qApp->processEvents();
    //QThread::msleep(sepO);
    delay(sepO);
    //取消录入等待标志
    waitInput = false;
}

void Widget::delay(int ms)
{

    QElapsedTimer elp;

    elp.start();
    while(true){

        qApp->processEvents();
        if(elp.elapsed() > ms){
            break;
        }
    }


}
